package com.tanhua.server.service;

import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.*;
import com.tanhua.model.domain.*;
import com.tanhua.model.dto.AnswerDto;
import com.tanhua.model.vo.*;
import com.tanhua.server.exception.BusinessException;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 灵魂测试的控制层
 *
 * @author 李磊
 * @since 2022-01-14 9:18
 */
@Service
public class TestSoulService {

    @Autowired
    RedisTemplate<String, String> redisTemplate;

    @DubboReference
    QuestionnaireApi questionnaireApi;

    @DubboReference
    SoulQuestionApi soulQuestionApi;

    @DubboReference
    OptionsApi optionsApi;

    @DubboReference
    ReportApi reportApi;

    @DubboReference
    ReportRelationshipApi reportRelationshipApi;
    @DubboReference
    TestIdentificationApi testIdentificationApi;

    @DubboReference
    UserInfoApi userInfoApi;

    /**
     * 说明:  进行用户的试卷查询
     *
     * @param userId 用户id
     * @return java.util.List<com.tanhua.model.vo.QuestionnaireVo>
     * @author 李磊
     * @since 2022-01-14 09:38
     */
    public List<QuestionnaireVo> findTestList(Long userId) {

        //查询所有问卷
        List<Questionnaire> questionnaireList = questionnaireApi.findAll();
        String testUnlockKey = Constants.Q_N_R + userId;
        //查询redis中的用户试卷解锁情况
        int unlockNumber = Integer.parseInt(Objects.requireNonNull(redisTemplate.opsForValue().get(testUnlockKey)));

        ArrayList<QuestionnaireVo> questionnaireVos = new ArrayList<>();
        for (Questionnaire questionnaire : questionnaireList) {

            QuestionnaireVo questionnaireVo = new QuestionnaireVo();
            BeanUtils.copyProperties(questionnaire, questionnaireVo);

            //unlockNumber= 默认值“1”---->则只有初级解锁
            //unlockNumber= “2”---->则只有初级解锁、中级解锁
            //unlockNumber= “3”---->则只有初级解锁、中级解锁、全部解锁
            if ("初级灵魂题".equals(questionnaireVo.getName())) {
                //设置初级灵魂题解锁
                questionnaireVo.setIsLock(0);
                //查询用户的初级报告id
                String primaryReportKey = Constants.PRIMARY_REPORT + userId;
                String primaryReportId = redisTemplate.opsForValue().get(primaryReportKey);
                if (primaryReportId != null) {
                    //设置初级报告id
                    questionnaireVo.setReportId(primaryReportId);
                }

            } else if (unlockNumber >= 2 && "中级灵魂题".equals(questionnaireVo.getName())) {
                //设置中级灵魂题解锁
                questionnaireVo.setIsLock(0);
                //查询用户的中级报告id
                String intermediateReportKey = Constants.INTERMEDIATE_REPORT + userId;
                String intermediateReportId = redisTemplate.opsForValue().get(intermediateReportKey);
                if (intermediateReportId != null) {
                    //设置中级报告id
                    questionnaireVo.setReportId(intermediateReportId);
                }
            } else if (unlockNumber == 3 && "高级灵魂题".equals(questionnaireVo.getName())) {
                //设置高级灵魂题解锁
                questionnaireVo.setIsLock(0);
                //查询用户的高级报告id
                String seniorReportKey = Constants.SENIOR_REPORT + userId;
                String seniorReportId = redisTemplate.opsForValue().get(seniorReportKey);
                if (seniorReportId != null) {
                    //设置高级报告id
                    questionnaireVo.setReportId(seniorReportId);
                }
            }

            //遍历集合获取每一个问卷的问题
            List<SoulQuestion> soulQuestionList = soulQuestionApi.findByQuestionnaireId(questionnaire.getId());
            ArrayList<SoulQuestionVo> questions = new ArrayList<>();
            for (SoulQuestion soulQuestion : soulQuestionList) {
                List<Options> optionsList = optionsApi.findByQuestionId(soulQuestion.getId());
                //获取每道题的选项集
                List<OptionsVo> optionsVos = optionsList.stream().map(OptionsVo::init).collect(Collectors.toList());
                //将选项集设置到每一个问题中
                SoulQuestionVo soulQuestionVo = SoulQuestionVo.init(soulQuestion, optionsVos);
                //将问题集添加到每一份试卷的问题集合中
                questions.add(soulQuestionVo);
            }
            //将问题集合设置到每一份试卷中
            questionnaireVo.setQuestions(questions);
            //将试卷添加到返回集合中
            questionnaireVos.add(questionnaireVo);
        }
        return questionnaireVos;
    }


    /**
     * 说明:  测试答题
     *
     * @param answers 答案集合
     * @param userId  用户id
     * @return java.lang.String
     * @author 李磊
     * @since 2022-01-14 14:44
     */
    public Long testSoul(List<AnswerDto> answers, Long userId) {
        //查询问题对应的试卷
        // TODO: 2022/1/14 默认一个问题只能在一个试卷中出现，即使出现，选项分值也不应该相同
        SoulQuestion soulQuestion = soulQuestionApi.findById(Long.valueOf(answers.get(0).getQuestionId()));
        //查询本次进行的试卷
        Questionnaire questionnaire = questionnaireApi.findById(soulQuestion.getQuestionnaireId());

        String reportIdKey;
        if ("初级灵魂题".equals(questionnaire.getName())) {
            reportIdKey = Constants.PRIMARY_REPORT + userId;
        } else if ("中级灵魂题".equals(questionnaire.getName())) {
            reportIdKey = Constants.INTERMEDIATE_REPORT + userId;
        } else if ("高级灵魂题".equals(questionnaire.getName())) {
            reportIdKey = Constants.SENIOR_REPORT + userId;
        } else {
            //试卷名称异常
            throw new BusinessException(ErrorResult.questionnaireNameError());
        }
        Report report = new Report();
        report.setUserId(userId);
        report.setQuestionnaireId(questionnaire.getId());
        int score = 0;
        for (AnswerDto answer : answers) {
            score = score + optionsApi.findScoreById(Long.valueOf(answer.getOptionId()));
        }
        report.setReportScore(score);

        reportApi.addReport(report);
        Report one = reportApi.findByUserId(userId, questionnaire.getId());

        //存储报告id和对应的试卷名到redis中--注意同一份报告的重复测试
        if (Boolean.TRUE.equals(redisTemplate.hasKey(reportIdKey))) {
            //如果已有，则删除旧的，存入新的
            redisTemplate.delete(reportIdKey);
        }
        redisTemplate.opsForValue().set(reportIdKey, one.getId().toString());

        //redis中查询用户解锁字段，如果没有，则设置为1，如果有则+1；
        String testUnlockKey = Constants.Q_N_R + userId;
        if (Boolean.TRUE.equals(redisTemplate.hasKey(testUnlockKey))) {
            Integer s = Integer.valueOf(redisTemplate.opsForValue().get(testUnlockKey));
            if (s <= questionnaire.getId()) {
                //如果当前试卷的类型对应的解锁进度大于等于redis中的值，则修改(用户在进行已解锁报告的重新测试)
                s++;
                redisTemplate.delete(testUnlockKey);
                redisTemplate.opsForValue().set(testUnlockKey, String.valueOf(s));
            }
        } else {
            //设置解锁等级为默认的"1"
            redisTemplate.opsForValue().set(testUnlockKey, String.valueOf(1));
        }

        //查询结果相近的报告（score+-5）
        List<Report> reportList = reportApi.findByScore(score + 5, score - 5);
        //查询用户报告关系表中的最进更新的.用户编号
        int relationMaxNumber = reportRelationshipApi.findMaxNumber(userId);
        //失效的关系数集合
        ArrayList<Integer> failedNumbers = new ArrayList<>();
        //准备添加的关系数据集合
        List<ReportRelationship> relationshipList = new ArrayList<>();

        //添加与本次报告结果相似的关系数据到报告关系表中
        for (Report item : reportList) {
            ReportRelationship relationship = new ReportRelationship();
            relationship.setUserId(userId);
            relationship.setSimilarYouUserId(item.getUserId());
            if (relationMaxNumber == 0) {
                //设置用户自己为相似对象，设置为1
                relationship.setSimilarYouNumber(1);
                //存入对应的redis标记
                redisTemplate.opsForValue().set(Constants.IS_ME + userId, userId.toString());
                relationship.setReportId(one.getId());
                relationMaxNumber++;
            } else {
                //设置新数据的用户编号
                if (relationMaxNumber <= 10000) {
                    relationship.setSimilarYouNumber(relationMaxNumber);
                } else {
                    //重置关系数,并删除对应的redis标记
                    relationMaxNumber = 1;
                    redisTemplate.delete(Constants.IS_ME + userId);

                    failedNumbers.add(relationMaxNumber);
                    relationship.setSimilarYouNumber(relationMaxNumber);
                }
                relationship.setReportId(item.getId());
            }
            relationMaxNumber++;
            relationshipList.add(relationship);
        }
        //添加新的报告关系到报告关系表表中
        reportRelationshipApi.addSmallRelation(userId, relationshipList, failedNumbers);

        return one.getId();
    }

    /**
     * 说明:  查询报告结果
     *
     * @param userId   用户id
     * @param reportId 报告id
     * @return com.tanhua.model.vo.TestIdentificationVo
     * @author 李磊
     * @since 2022-01-15 22:15
     */
    public TestIdentificationVo findTestResult(Long userId, Long reportId) {

        Report report = reportApi.findById(reportId);
        Integer score = report.getReportScore();
        //根据成绩查询，对应的报告描述
        TestIdentification result = testIdentificationApi.findByScore(score);
        //封装维度度数据
        List<DimensionVo> dimensions = new ArrayList<>(4);

        dimensions.add(0, new DimensionVo("外向", "80%"));
        dimensions.add(1, new DimensionVo("判断", "70%"));
        dimensions.add(2, new DimensionVo("抽象", "90%"));
        dimensions.add(3, new DimensionVo("理性", "60%"));

        //查询和你相似的关系数据（只要十条）
        List<ReportRelationship> relationshipList = reportRelationshipApi.findSimilarYou(userId);

        List<SimilarYouVo> similarYou = new ArrayList<>();

        //查看当前的”1“用户编号是不是自己
        boolean hasMe = Boolean.TRUE.equals(redisTemplate.hasKey(Constants.IS_ME + userId));
        //标记容器中的真实数据数量，不足的用之前填充的数据，随机补足数组的大小为10
        int j = 0;
        for (int i = 0; i < relationshipList.size(); i++) {
            ReportRelationship r = relationshipList.get(i);
            SimilarYouVo svo = new SimilarYouVo();
            UserInfo userInfo = userInfoApi.findById(r.getSimilarYouUserId());
            Integer userNumber = r.getSimilarYouNumber();
            svo.setId(userNumber);
            if (userNumber == 1 && hasMe) {
                //当前的一号用户是不是自己
                svo.setAvatar(userInfoApi.findById(userId).getAvatar());
            } else {
                //用户信息可能创建不完全
                if (userInfo != null && userInfo.getAvatar() != null) {
                    svo.setAvatar(userInfo.getAvatar());
                }
            }
            similarYou.add(svo);
            j = i + 1;
        }
        //不足的用之前填充的数据，随机补足数组的大小为10
        if (j != 10) {
            //说明用户数没有取够，将已经存入的数据进行第二次添加
            Random random = new Random();
            do {
                similarYou.add(similarYou.get(random.nextInt(j) + 1));
            } while (similarYou.size() != 10);
        }
        TestIdentificationVo vo = new TestIdentificationVo();
        vo.setConclusion(result.getConclusion());
        vo.setCover(result.getCover());
        vo.setDimensions(dimensions);
        vo.setSimilarYou(similarYou);
        System.out.println(vo);
        return vo;
    }
}
